package cn.itcast.hotel;

import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author mrchen
 * @date 2022/2/16 14:32
 */
@SpringBootTest
public class HotelSearchDemo {
    RestHighLevelClient client;

    /**
     * 按照品牌分组
     * @throws IOException
     */
    @Test
    public void aggregations() throws IOException {
       // 1. 创建请求
        SearchRequest request = new SearchRequest("hotel");

        request.source().aggregation(
                AggregationBuilders.terms("termsByBrand").field("brand").size(30)
        );
        request.source().size(0);
        // 2. 执行请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 3. 解析结果
        // 聚合结果
        Aggregations aggregations = response.getAggregations();
        // 根据自定义的名称 找到指定的聚合结果
        Terms terms = aggregations.get("termsByBrand");
        // 获取bucket 分组信息
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        // 遍历分桶集合
        for (Terms.Bucket bucket : buckets) {
            System.out.println("=================================================");
            System.out.println("当前分组的key:  " + bucket.getKeyAsString());
            System.out.println("当前分组文档的数量: " + bucket.getDocCount());
            System.out.println("=================================================");
        }
    }
    @Test
    public void highlight() throws IOException {
        // 1. 创建搜索请求
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        // 基础条件
        source.query(QueryBuilders.matchQuery("all","外滩如家"));
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name"); // 哪个字段高亮
        highlightBuilder.preTags("<span style='color:green'>"); // 加什么前置标签
        highlightBuilder.postTags("</span>");  // 加什么后置标签
        highlightBuilder.requireFieldMatch(false);  // 关闭字段名称校验
        source.highlighter(highlightBuilder);
        // 2. 执行搜索请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 3. 解析相应结果
        handleResponse(response);
    }

    /**
     * 排序  分页
     * @throws IOException
     */
    @Test
    public void sortAndPage() throws IOException {
        int page = 2; // 当前页
        int pageSize = 5; // 每页条数
        // 1. 创建搜索请求
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        // 基础条件
        source.query(QueryBuilders.matchQuery("all","外滩如家"));
        source.from((page - 1) * pageSize);
        source.size(pageSize);
        source.sort("score", SortOrder.DESC);
        source.sort("price", SortOrder.ASC);
        // 2. 执行搜索请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 3. 解析相应结果
        handleResponse(response);
    }
    /**
     * 查询 match  all 外滩
     * 价格:  > 200  < 500
     * 品牌 如家
     * @throws IOException
     */
    @Test
    public void bool() throws IOException {
        // 1. 创建搜索请求
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //  * 查询 match  all 外滩
        boolQuery.must(QueryBuilders.matchQuery("all","外滩"));
        // * 价格:  > 200  < 500
        boolQuery.must(QueryBuilders.rangeQuery("price").gt(200).lt(500));
        // * 品牌 如家
        boolQuery.must(QueryBuilders.termQuery("brand","如家"));
        // 基础条件
        source.query(boolQuery);
        // 2. 执行搜索请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 3. 解析相应结果
        handleResponse(response);
    }

    @Test
    public void range() throws IOException {
        // 1. 创建搜索请求
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        // 基础条件
        source.query(QueryBuilders.rangeQuery("price").gte(100).lte(500));
        // 2. 执行搜索请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 3. 解析相应结果
        handleResponse(response);
    }
    @Test
    public void term() throws IOException {
        // 1. 创建搜索请求
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        // 基础条件
        source.query(QueryBuilders.termQuery("price",689));
        // 2. 执行搜索请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 3. 解析相应结果
        handleResponse(response);
    }
    @Test
    public void match() throws IOException {
        // 1. 创建搜索请求
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        // 基础条件
        source.query(QueryBuilders.matchQuery("all","外滩如家"));
        // 2. 执行搜索请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 3. 解析相应结果
        handleResponse(response);
    }
    @Test
    public void matchAll() throws IOException {
        // 1. 创建搜索请求
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        // 基础条件
        source.query(QueryBuilders.matchAllQuery());
        // 2. 执行搜索请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 3. 解析相应结果
        handleResponse(response);
    }
    private void handleResponse(SearchResponse response){
        SearchHits hits = response.getHits();
        System.out.println("满足条件结果数量: " + hits.getTotalHits().value);
        SearchHit[] docArr = hits.getHits();
        for (SearchHit doc : docArr) {
            String hotelJson = doc.getSourceAsString();
            // 查询source文档内容
            HotelDoc hotelDoc = JSON.parseObject(hotelJson, HotelDoc.class);

            // 单独获取高亮结果
            Map<String, HighlightField> highlightFields = doc.getHighlightFields();
            if (!CollectionUtils.isEmpty(highlightFields)) {
                HighlightField highlightField = highlightFields.get("name");
                // 获取高亮的处理结果
                String nameResult = highlightField.getFragments()[0].toString();
                // 使用高亮结果覆盖name字段
                hotelDoc.setName(nameResult);
            }
            System.out.println(hotelDoc);
        }
    }

    @BeforeEach
    public void init(){
        client = new RestHighLevelClient(
                RestClient.builder(HttpHost.create("http://192.168.200.130:9200")));
    }
    @AfterEach
    public void close(){
        try {
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
